#include <unistd.h>
#include <cerrno>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <sys/poll.h>

#include "dataDevice.h"
#include "readConfig.h"

using namespace std;

const char ConfigFile[] = "config";
static const int timeout = 5; //seconds
char buff[65535];
char package[65535];
int packageIndex = 0;

int main(int argc, char **argv)
{
  int res;

  //----------------------------------------------------------------------------------
  //Get conf
  /*get configure info*/
  Config configSettings(ConfigFile);

  /* get device configure */
  string deviceName;
  deviceName = configSettings.Read("dataDeviceName", deviceName);
  cout<<"Serial device"<<endl;

  /*get data server configure*/
  string dataServerAddress;
  dataServerAddress = configSettings.Read("dataServerAddress", dataServerAddress);
  int dataServerPort = configSettings.Read("dataServerPort", 8080);
  cout<<"Data server address: "<<dataServerAddress<<" ,Port: "<<dataServerPort<<endl;

  /* create device */
  dataDevice *device;
  if(deviceName == "serial")
  {
    string dataDeviceSerial;
    dataDeviceSerial = configSettings.Read("dataDeviceSerial", dataDeviceSerial);
    device = new serialDataDevice(dataDeviceSerial.c_str());
  }

  //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  /* open device */
  device->open();

  /* create socket for receive cmd */
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  if(fd == -1)
  {
    cerr<<"Create socket for receive cmd error: "<<strerror(errno)<<endl;
    return -1;
  }
  cout<<"socket fd = "<<fd<<endl;

  /*build data server address*/
  struct sockaddr_in saddr;
  bzero(&saddr, sizeof(struct sockaddr_in));
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(dataServerPort);
  inet_pton(AF_INET, dataServerAddress.c_str(), &saddr.sin_addr);

  struct pollfd fds[1];
  //UDP file descriptor
  fds[0].fd = device->getFd();
  fds[0].events = POLLIN;

  while(true)
  {
    res = poll(fds, 1, -1);
    if(res < 0)
    {
      cout<<"Poll error, exit...."<<endl;
      exit(1);
    }
    else if(res == 0)
    {
      cout<<"Poll timeout"<<endl;
      continue;
    }

    /* data from searial */
    if(fds[0].revents & POLLIN)
    {
      res = device->read(package + packageIndex, sizeof(package) - packageIndex);
			for(int i=0;i<res;i++)
			  printf("%02hhx ", package[packageIndex + i]);
			cout<<endl;

      cout<<"Node: Read "<<res<<" bytes from device"<<endl;
      if(res == 0)
      {
        cout<<"Disconnected from device"<<endl;
        break;
      }
      else if(res < 0)
      {
        if(errno == EINTR)
          continue;
        cout<<"device error"<<endl;
        exit(1);
      }
      else if(res > 0)
      {
        char* start = package; /*Start of package*/
        int len = res + packageIndex; /* Length of data left*/
        /* Scan and send packages*/
		while(true)
		{
		  /*Find package tail*/
	      char* end = (char *)memmem(start, len, "\x13\x10", 2);

          /* Have end flag*/
	      if(end)
	      {
		    /**** send data to gateway ******/
	        if(memmem(start, end - start + 2, "\x55\xAA", 2) == start) /* Check end flag */
	        {
					    cout<<"Send:"<<endl;
					    for(int i =0;i<end-start+2;i++)
							  printf("%02hhx", start[i]);
							cout<<endl;
              res = sendto(fd, start, end - start + 2, 0, (struct sockaddr *)&saddr, sizeof(struct sockaddr));
              cout<<"Send "<<res<<" bytes to data server"<<endl;
	        }
            /**** send data to gateway end ******/

            len -= end - start + 2;
            start = end + 2;
          }
	      else
	        break;
        }//end while
	
        if(start != package) /* Send one or more package*/
          for(int i = 0; i < len; i++)
	        package[i] = start[i];

	    packageIndex = len;
      }
    }//end if
  }//end while
  
  close(fd); //close listen fd
  return 0;
}//end main
